package com.example.blog.modules.article.service.impl;

import com.example.blog.common.exception.ServiceException;
import com.example.blog.common.security.SecurityService;
import com.example.blog.modules.article.dto.CommentDTO;
import com.example.blog.modules.article.dto.CommentRequest;
import com.example.blog.modules.article.entity.Article;
import com.example.blog.modules.article.entity.Comment;
import com.example.blog.modules.article.repository.ArticleRepository;
import com.example.blog.modules.article.repository.CommentRepository;
import com.example.blog.modules.article.service.CommentService;
import com.example.blog.modules.user.entity.User;
import com.example.blog.modules.user.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class CommentServiceImpl implements CommentService {

    private final CommentRepository commentRepository;
    private final ArticleRepository articleRepository;
    private final UserRepository userRepository;
    private final SecurityService securityService;

    @Override
    @Transactional
    public CommentDTO createComment(CommentRequest request) {
        Article article = articleRepository.findById(request.getArticleId())
                .orElseThrow(() -> new ServiceException("文章不存在"));
        
        if (!article.getAllowComment()) {
            throw new ServiceException("该文章已关闭评论功能");
        }
        
        User currentUser = userRepository.findByUsername(securityService.getCurrentUsername())
                .orElseThrow(() -> new ServiceException("用户不存在"));
        
        Comment comment = new Comment();
        comment.setContent(request.getContent());
        comment.setArticle(article);
        comment.setUser(currentUser);
        
        if (request.getParentId() != null) {
            Comment parent = commentRepository.findById(request.getParentId())
                    .orElseThrow(() -> new ServiceException("父评论不存在"));
            comment.setParent(parent);
        }
        
        comment = commentRepository.save(comment);
        articleRepository.incrementCommentCount(article.getId());
        
        return convertToDTO(comment);
    }

    @Override
    @Transactional
    public void deleteComment(Long id) {
        Comment comment = commentRepository.findById(id)
                .orElseThrow(() -> new ServiceException("评论不存在"));
        
        // 检查权限
        if (!securityService.isCurrentUser(comment.getUser().getId()) && 
            !securityService.hasRole("ROLE_ADMIN")) {
            throw new ServiceException("没有权限删除此评论");
        }
        
        // 删除子评论
        List<Comment> children = commentRepository.findByParentId(id);
        commentRepository.deleteAll(children);
        
        // 更新文章评论数
        Long articleId = comment.getArticle().getId();
        articleRepository.decrementCommentCount(articleId);
        children.forEach(child -> articleRepository.decrementCommentCount(articleId));
        
        commentRepository.delete(comment);
    }

    @Override
    @Transactional(readOnly = true)
    public CommentDTO getComment(Long id) {
        return convertToDTO(commentRepository.findById(id)
                .orElseThrow(() -> new ServiceException("评论不存在")));
    }

    @Override
    @Transactional(readOnly = true)
    public Page<CommentDTO> getArticleComments(Long articleId, Pageable pageable) {
        return commentRepository.findByArticleIdAndParentIsNull(articleId, pageable)
                .map(this::convertToDTO);
    }

    @Override
    @Transactional(readOnly = true)
    public List<CommentDTO> getCommentReplies(Long commentId) {
        return commentRepository.findByParentId(commentId)
                .stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional
    public void incrementLikeCount(Long id) {
        commentRepository.incrementLikeCount(id);
    }

    @Override
    @Transactional
    public void decrementLikeCount(Long id) {
        commentRepository.decrementLikeCount(id);
    }

    @Override
    @Transactional
    public void approveComment(Long id) {
        commentRepository.approve(id);
    }

    @Override
    @Transactional(readOnly = true)
    public long getApprovedCommentCount(Long articleId) {
        return commentRepository.countByArticleIdAndApproved(articleId);
    }

    private CommentDTO convertToDTO(Comment comment) {
        CommentDTO dto = new CommentDTO();
        dto.setId(comment.getId());
        dto.setContent(comment.getContent());
        dto.setArticleId(comment.getArticle().getId());
        dto.setUser(convertToUserDTO(comment.getUser()));
        
        if (comment.getParent() != null) {
            dto.setParentId(comment.getParent().getId());
        }
        
        List<Comment> children = commentRepository.findByParentId(comment.getId());
        if (!children.isEmpty()) {
            dto.setChildren(children.stream()
                    .map(this::convertToDTO)
                    .collect(Collectors.toList()));
        }
        
        dto.setLikeCount(comment.getLikeCount());
        dto.setIsApproved(comment.getIsApproved());
        dto.setCreateTime(comment.getCreateTime());
        dto.setUpdateTime(comment.getUpdateTime());
        
        return dto;
    }

    private com.example.blog.modules.user.dto.UserDTO convertToUserDTO(User user) {
        com.example.blog.modules.user.dto.UserDTO dto = new com.example.blog.modules.user.dto.UserDTO();
        dto.setId(user.getId());
        dto.setUsername(user.getUsername());
        dto.setNickname(user.getNickname());
        dto.setAvatar(user.getAvatar());
        return dto;
    }
} 